﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Fortuitus.Core
{
    public interface IVector : IEnumerableArray<double>
    {
        /// <summary>
        /// The length of the vector.
        /// </summary>
        int Length { get; }

        /// <summary>
        /// Checks whether a certain metadata key exists.
        /// </summary>
        /// <param name="metaDataKey">The metadata key to check</param>
        /// <returns>A value indicating whether the metadata exists.</returns>
        bool HasValue(string metaDataKey);

        /// <summary>
        /// Access metadata value with a specific key. 
        /// </summary>
        /// <param name="metaDataKey">The metadata key to access the stored value.</param>
        /// <returns>The metadata value.</returns>
        object GetValue(string metaDataKey);

        /// <summary>
        /// Sets a metadata value with a specific key. If the key already exists then the value will be overriden. 
        /// </summary>
        /// <param name="metaDataKey">The key that's used to store the metadata.</param>
        /// <param name="value">The value to store in the metadata store.</param>
        void SetValue(string metaDataKey, object value);

        /// <summary>
        /// Generic version to access metadata value with a specific key. 
        /// </summary>
        /// <typeparam name="T">The type of the value expected. If the stored value of a different type then an exception will be thrown.</typeparam>
        /// <param name="metaDataKey">The key to access the metadata.</param>
        /// <returns>The stored value.</returns>
        T GetValue<T>(string metaDataKey);

        /// <summary>
        /// Generic version to set metadata value with a specific key. If the key already exists then the value will be overriden. 
        /// </summary>
        /// <typeparam name="T">The type of the value expected.</typeparam>
        /// <param name="metaDataKey">The key to store the metadata.</param>
        /// <param name="value">The stored value of type T</param>
        void SetValue<T>(string metaDataKey, T value);

        /// <summary>
        /// Gets a metric of the this vector.
        /// </summary>
        /// <param name="metricKey">The name of the metric.</param>
        /// <returns>The value of the metric.</returns>
        double GetMetric(string metricKey);

        /// <summary>
        /// Sets a metric with a specific function.
        /// </summary>
        /// <param name="metricKey">The access key for the metric.</param>
        /// <param name="metricFunction">The function to calculate the metric.</param>
        /// <param name="lazyCalculation">An value that indicates whether the metric shoulds be calulated immediately or if needed.</param>
        void SetMetric(string metricKey, Func<IVector, double> metricFunction, bool lazyCalculation = true);

        /// <summary>
        /// An event that informs subscriber that the vector has changed.
        /// </summary>
        event EventHandler Changed;
    }
}
